home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Gold 2
/
Shareware Gold II - Volume 2 Number 1 - Wayzata Technology (7071) (1991).iso
/
business
/
zipkey
/
zprog.doc
< prev
Wrap
Text File
|
1990-10-14
|
32KB
|
791 lines
PROGRAMMATIC INTERFACE DOCUMENT
This file is intended for computer programmers who wish to access
ZIPKEY directly from within their programs. If you are not a
computer programmer, you may ignore this file.
The ZIPKEY Interrupt
When ZIPKEY is installed as a memory-resident program (using the
ZIPKEY 4 command), it takes over one of the 8086's interrupts,
INT 179 (decimal; it's B3 in hexadecimal). This interrupt serves
two functions: first, it is the method by which ZIPKEY detects if
it has already been installed. Second, it provides the interface
by which computer programs can call ZIPKEY directly, to obtain
zipcode-related services.
I conducted a survey of numerous computers before selecting INT
179 to be used by ZIPKEY. I found no computers or peripherals
that use this interrupt, and I am hopeful that there are none.
If your computer does use INT 179, then ZIPKEY and the device or
program using INT 179 will interfere with each other. You can
change the interrupt number ZIPKEY uses by modifying the ZIPKEY
program itself: the number 179 is stored in the fourth byte of
the ZIPKEY program code, immediately beyond the three-byte JMP
instruction that begins the program. This JMP occurs at the very
start of the ZIPKEY.COM file, or immediately beyond the 512-byte
header of the ZIPKEY.EXE file. You can use a debugger or a hex
editor to modify the byte to an unused interrupt number.
Testing for ZIPKEY's Presence
Before you program attempts to call ZIPKEY, it may wish to verify
that ZIPKEY has been installed, and report an error if it isn't.
Otherwise, you program may crash when it tries to call code that
isn't there.
You can test for ZIPKEY's presence by examining the INT 179
handler, whose doubleword pointer is stored at offset 179*4 (=716
=02CCH) within segment 0 of the 8086 memory space. If ZIPKEY is
installed, the doubleword points to its code segment. Location
075H within that code segment contains the signature string
ZIPKEY. Thus, the following code sequence will check for
ZIPKEY's presence:
P-2
OUR_ZIPKEY: ; our copy of the template
DB 'ZIPKEY'
CHECK_FOR_ZIPKEY:
PUSH DS ; save register value
SUB AX,AX ; load zero
MOV DS,AX ; point DS to 0 -- 8086 interrupts
MOV DS,WORD PTR 02CEH ; fetch the segment part of INT 179
MOV SI,075H ; point to signature in segment
PUSH CS ; push our code segment
POP ES ; set ES to our code segment
MOV DI,OFFSET OUR_ZIPKEY ; now ES:DI points to 'ZIPKEY'
MOV CX,3 ; there are 3 words in 'ZIPKEY'
REPE CMPSW ; does DS:75H point to 'ZIPKEY'?
POP DS ; restore register before jumping
JZ ZIPKEY_INSTALLED ; jump if it does match
ZIPKEY_NOT_INSTALLED: ; it does not match
Following the ZIPKEY signature, at offset 07BH within the ZIPKEY
code segment, is a single byte that is zero in the initial
version of ZIPKEY, but will increment each time I release a
ZIPKEY with new features or any other changes to the programmatic
interface. That way, if you program needs ZIPKEY to be of a
sufficiently recent version, it can ensure that it is. (You can
also use the version number returned by the ZK_VERSION function
described shortly.)
ZIPKEY Calling Conventions
ZIPKEY's interface works similarly to that of the MS-DOS
operating system, or the LIM-EMS specification. The interface is
specified in 8086 assembly language. You load a function number
into the AH register, and possibly other input parameters into
other registers, then you execute an INT instruction with an
appropriate interrupt number -- in ZIPKEY's case, the INT 179
instruction.
When ZIPKEY has completed the function, it returns control to
your program at the instruction following the INT 179. The
success of the call is indicated by the Carry flag: NoCarry (flag
= 0) indicates success; Carry (flag = 1) indicates failure. If
the Carry flag is set, AL is usually set to an error code (the
exceptions are those functions which, as mentioned in their
following descriptions, return the state code for a suggested
city). Here are the possible error codes:
0FDH is returned if ZIPKEY is busy. You will get this error only
if the program calling ZIPKEY had interrupted another
program which also happened to be in the middle of a ZIPKEY
call. ZIPKEY is not reentrant, so it must refuse calls in
this situation. If you think this interrupted-programming
scenario is possible, you should check for this possibility.
If ZIPKEY is busy, you should give the interrupted code a
chance to complete the ZIPKEY call, and try your call again
later.
P-3
0FEH is returned if you provided an illegal function number in
the AH register.
0FFH is returned if the searching function requested failed to
find a valid entry, or even a suggested value.
Here are ZIPKEY's register-preserving conventions: The AX
register is clobbered by an INT 179 call; but all other 8086
machine registers are preserved unless they are specifically
named as having return values. If a function returns an error,
such return registers may be clobbered even if they contain no
values in the return case. For example, the ZK_STCITY_ZIP
function returns values in BH, CX, and DX. Except for AX, all
other registers not mentioned are preserved (SI,DI,BP,DS,ES).
The BH, CX, and DX registers may be clobbered even if the search
fails (and Carry is returned).
The ZIPKEY Functions
Following are the functions available to you when ZIPKEY is
installed. For each function, you load the input registers with
the values indicated, then invoke INT 179.
The names of the functions (ZK_VERSION, ZK_ABBR_ST, etc.) have no
significance to ZIPKEY-- I present them merely as suggested names
if you wish to implement a library of calls; and also so that I
can refer to the functions by name.
ZK_VERSION: returns ZIPKEY version information.
In: AH = 070H
Out: AX = The ZIPKEY program version number, as shown when
ZIPKEY is invoked or the ZIPKEY window is popped up. AH
is the major version number (to the left of the decimal
point) and AL is the minor version number (to the right
of the decimal point). For example, for V1.0 the return
AX value would be hex 100.
CL = The number of states, (and territories, etc.) in the
current database. Each state is assigned an internal
numeric code by ZIPKEY, that is used by many of the
functions of ZIPKEY's programmatic interface. These
codes range from 0 to CL-1.
DX = The date of the current ZIPKEY.OVL database. DL is
the month, ranging from 1 for January to 12 for
December. DH is the year minus 1900; e.g., decimal 89
for 1989.
P-4
ZK_ABBR_ST: converts a two-letter abbreviation into a state
code.
In: AH = 071H
BX = The 2-letter ASCII abbreviation for the state, in
either upper- or lower-case. BL is the first letter and
BH is the second letter.
Out: AL = The ZIPKEY state code, suitable for input to other
ZIPKEY functions in this chapter.
AL = 0FFH with the Carry flag set if not found.
ZK_ST_ABBR: converts a state code into a two-letter
abbreviation.
In: AH = 072H
BL = The ZIPKEY state code, ranging from 0 through CL-1,
where CL is returned by ZK_VERSION.
Out: AX = The 2-letter ASCII abbreviation, upper case. AL is
the first letter and AH is the second letter.
The Carry flag is set if the input state code BL was
invalid.
ZK_ST_NAME: converts a state code into a full state name.
In: AH = 073H
BL = The ZIPKEY state code, as returned by ZK_ABBR_ST.
ES:DI points to the buffer to contain the returned state
name.
Out: The full state name is output to ES:DI-pointed memory. DI
is advanced beyond the output.
The Carry flag is set if the input state code BL was invalid.
P-5
ZK_ZIP_DIGITS: converts zipcode DXCH into a ASCII digits string.
In: AH = 074H
DX = The zip region, ranging from 0 to 999.
CH = The last 2 digits of the zipcode, from 0 to 99. Or,
if you want only 3 digits output, set CH to 255.
Out: The 5 ASCII decimal digits of the zipcode are output to
ES:DI-pointed memory. DI advanced beyond the output.
The Carry flag is set if DX was greater than 999.
NOTE this is not really a database function-- it is just
an unpacking function provided for convenience.
ZK_ZIP_ST: looks up the state code for zipcode DXCH.
In: AH = 075H
DX = The zip region, ranging from 0 to 999.
CH = The last 2 digits of the zipcode, from 0 to 99.
Out: AL = the ZIPKEY state code.
BX = the area code.
The Carry flag is set, and AL=0FFH, if the zipcode
region (the first three digits) is invalid.
Note: for speed, this routine does not check for validity
of the individual zipcode: it looks at only the zip
region and the state-exceptions list. If you wish to
check the validity of a zipcode, use ZK_ZIP_CITY instead.
P-6
ZK_ZIP_CITY: looks up the state and city for zipcode DXCH.
In: AH = 076H
DX = The zip region, ranging from 0 to 999.
CH = The last 2 digits of the zipcode, from 0 to 99.
ES:DI points to the buffer to contain the returned city
name.
Out: The ZIPKEY state code is returned in the AL register,
and the area code in the BX register. The
city name is output to ES:DI-pointed memory. DI is
advanced beyond the output. To ensure that the name does
not exceed a maximum width, you can set the width using the
ZK_RESTORE function. The Carry flag is set if the zipcode
was not found, with AL/DI set to the suggested state/city
if there is one. AL is set to 0FFH if there is no
suggested city.
NOTE that a previous call to ZK_ZIP_ST can and should be
made if you wish to suppress output for the not-found-but-
suggested case.
ZK_ZIP_KEYS: plays the back exit key BX for the entry with
zipcode DXCH.
In: AH = 077H
BX = The 16-bit BIOS keycode for a defined ZIPKEY alternate
exit key. This is the code returned in the AX register
after you call the keyboard service routine (MOV AH,0
followed by INT 016H). For example, the code for the F1
function key on a 100% IBM-compatible is 03B00H; add
0100H for subsequent function keys.
DX = The zip region, ranging from 0 to 999.
CH = The last 2 digits of the zipcode, from 0 to 99.
Out: If there is a failure with no suggested city, ZIPKEY
returns Carry to the caller. Otherwise, it returns
NoCarry, and the zipcode specification defined by the BX
exit-key is inserted into the BIOS keystrokes buffer, as if
a user had popped up the ZIPKEY window, typed in the
zipcode, and exited with the BX exit key.
P-7
ZK_STCITY_ZIP: looks up the zipcodes for a given state and city.
In: AH = 078H
BL = The ZIPKEY state code for the city to be looked up.
DS:SI points to the city-name specification. The
specification is a string of ASCII characters,
terminated by a carriage-return (0DH) if the complete
name has been given, terminated by a null (00H) if
ZIPKEY should match any city whose name begins with the
specification, whether or not that is the complete city
name. Letters in the string can be in either upper- or
lower-case. ZIPKEY will also unabbreviate the string,
as described in Chapter 2.
Out: ZIPKEY accumulates a list of all cities that match the
specification given. The list is sorted first
alphabetically by city name, then numerically by zipcode.
Each entry on the list is a range of zipcodes for a city
that matches the specification. If the first and last
zipcodes in the range are the same, the range consists of
just the one zipcode. If they are different, then they
both represent valid codes for a matching city. Any
zipcodes between the first and last may be either valid
zipcodes for the same city, or undefined zipcodes.
The capacity of ZIPKEY's matching-entries buffer is 50. If
there are more than 50 entries for the specification,
ZIPKEY will return a count of 51 entries. You may make
calls to ZK_CASE_ZIP to determine the entries returned, but
be aware that unless the complete count happened to be 51,
the list is incomplete. The only way to obtain the
complete list of entries is to extend the city-name
specification by adding one or more letters in all possible
combinations.
The zipcode range for the first entry is returned with this
call. To obtain the remaining entries, you make repeated
calls to ZK_CASE_ZIP. To obtain a readable display for
each entry, you call ZK_ZIP_CITY, ZK_ZIP_ST, and
ZK_ZIP_DIGITS.
The return register values are:
BH = The number of matching entries (Carry set if BH=0). If
ZIPKEY's entries-buffer overflowed, BH is set to 51 (see
the above discussion about capacity).
DX = The zip region (0 to 999) of the first entry.
CL = The value of the bottom two digits for the first
zipcode in the range.
CH = The value of the bottom two digits for the last
zipcode in the range.
P-8
ZK_CITY_ZIP: looks up zipcodes for a given city.
In: AH = 079H
BL = The ZIPKEY state code of the first state to be
searched.
DS:SI points to the city-name specification, just as in
ZK_STCITY_ZIP.
Out: ZIPKEY accumulates a list of zipcode ranges, just as in
ZK_STCITY_ZIP. With this function, however, if no matching
entries are found for state BL, then BL is incremented to
search in the next state. Searching continues until either
a match is found or the last state code is reached. If
there is no matching entry for the last state, ZIPKEY
returns AL=0FFH with the Carry flag set. This differs from
the city-only search that is initiated interactively from
ZIPKEY's popup window-- the interactive search cycles
around to the first state and continues looking from there.
To get a complete list of matching cities for all states,
you call this function first with BL=0, then repeat the
call with BL set to the previous returned AL+1, until you
get a failed find.
The return register values are:
AL = The ZIPKEY state code of the first matching state. AL
is set to 0FFH with Carry set if no state was found.
BH = The number of matching entries (Carry set if BH=0). If
ZIPKEY's entries-buffer overflowed, BH is set to 51.
DX = The zip region (0 to 999) of the first entry.
CL = The value of the bottom two digits for the first
zipcode in the range.
CH = The value of the bottom two digits for the last zipcode
in the range.
P-9
ZK_CASE_ZIP: fetches an entry from a previous ZK_(ST)CITY_ZIP
call.
In: AH = 07AH
BL = a case number, from 0 to BH-1, where BH is the number
returned by the last call to ZK_STCITY_ZIP or
ZK_CITY_ZIP.
Out: AL = The ZIPKEY state code for this entry. Note that this
is the same value for all entries returned by a given
call to ZK_STCITY_ZIP or ZK_CITY_ZIP.
DX = The zip region (0 to 999).
CL = The bottom 2 digits (0 to 99) of the first zipcode in
the range.
CH = the bottom 2 digits (0 to 99) of the last zipcode in
the range. CH = CL if there is only one zipcode.
ZK_SAVE: fetches values necessary to save ZIPKEY's context.
In: AH = 07BH
Out: BL = maximum number of characters for a ZK_ZIP_CITY city name.
BH = the ZIPKEY state code for the last city-name search.
BH = 0FF if there is no previous ZK_STCITY_ZIP or
ZK_CITY_ZIP call.
CXDX = internal codes identifying the last city search
This function is provided just in case somebody wishes to
incorporate ZIPKEY into a multitasking system, in which
more than one task might be using ZIPKEY. The task-
switching code must call ZK_SAVE, record BX,CX, and DX as
part of the task state, and feed those values to ZK_RESTORE
before restarting the task.
ZK_SAVE can also be used to read the current setting for
the maximum city width, returned in the BL register.
P-10
ZK_RESTORE: restores ZIPKEY's context from a previous ZK_SAVE call.
In: AH = 07CH
BL = the maximum number of characters for a city name.
BH = the ZIPKEY state code returned by a previous ZK_SAVE
call.
BH = 0FF if you are just setting the city width.
CXDX = internal codes returned by a previous ZK_SAVE call.
Out: Carry if BH,CX,DX are not codes which could have been
returned by a previous ZK_SAVE call
This function will be used most often to set the maximum
city width. It is also used in multitasking systems, as
described under the previous function ZK_SAVE.
ZK_POPUP: pops up a ZIPKEY window from a program.
In: AH = 07DH
BL = an index number if you wish to simulate the pressing of
a hotkey.
BL = 0FF for immediate popup with nothing played back after
a confirming Enter key.
Out: ZIPKEY takes action as if the hotkey indexed by BL has been
pressed. This typically includes popping up a window,
waiting for the user to type a zipcode specification, and
playing back an indicated sequence through the BIOS
keystrokes buffer. The values of BL are defined by the
listing of hotkeys available from the configuration editing
menu: BL=0 for the first hotkey, BL=1 for the second, etc.
If BL is not a valid index ZIPKEY pops up a window, then
plays back nothing if a confirming Enter is given (ZIPKEY
will play back alternate exit keys, however). ZIPKEY does
not return from this interrupt call until the window is
popped away-- then it returns NoCarry.
P-11
ZK_REGION_CITY: outputs the name of the primary city for a
zipcode region.
In: AH = 07EH
DX = The zip region, ranging from 0 to 999.
ES:DI points to the buffer to contain the returned city
name.
Out: AL = The ZIPKEY state code for the region if the region
exists. BX is set to the area code.
The name of primary city for this region is output
to ES:DI-pointed memory. DI is advanced beyond the output.
AL = 0FF with the Carry flag set if the region does not
exist.
ZK_SWITCH: enables/disables hotkeys and/or DOS recursion checking.
In: AH = 07FH
BL = a control code:
0 for turn off hotkeys
1 for turn on hotkeys
2 for no change, just return hotkey status
3 for toggle hotkey status
6 for disabling DOS recursion checking
Out: The activation of hotkeys is disabled/enabled/reported.
When a hotkey is disabled ZIPKEY ignores it, and it reverts
to its non-ZIPKEY functionality. AL is returned set to the
hotkeys status: 0 for off (disabled), 1 for on (enabled).
If BL=6, ZIPKEY's program interface
(INT 179) no longer checks
to see if DOS is busy and cannot be called. It is the calling
program's responsibility to insure that DOS can be called.
ZK_AREA_ST: Delivers the state associated with area code BX.
In: AH = 080H
BX = area code (decimal integer)
Out: AL = the ZIPKEY state code for the area code, if the area code
exists. DX is set to the first zip region associated with that
state, and CX to the number of zip regions until the last
region associated with the state. You must make CX subsequent
calls to ZK_REGION_CITY to find which regions are actually within
the state, and/or contain the area code wanted.
If the area code is Canadian, we return a special state code
that will be honored by ZK_ST_ABBR and ZK_ST_NAME, but the
region DX is set to 1000. If the area code does not exist,
we return Carry, AL=0FFH and DX=1001.
P-12
Sample Program Code
Following are fragments of assembly-language code that call
ZIPKEY's programmatic interface. I've tried to make them
compatible with all the major assemblers, although they are
tested only against my A86 assembler. If you do use my A86
assembler, and you reuse the local labels L3, L4, L6, L8, and L10
elsewhere in your program, you should insert ">" into their
forward references in the following code: JC >L3; JC >L4; JMP
>L6, JNE >L8, JE >L10.
RO_NAME:
DB 'RO',0
NOME_NAME:
DB 'nome',0DH
; output a list of states to memory at 08000H
L0:
MOV AH,070H ; ZIPKEY function number ZK_VERSION
INT 179 ; fetch the version information
MOV CH,0 ; extend states count CL to CX
MOV BL,0 ; load the first state code
MOV DI,08000H ; load the output pointer
L1: ; loop here to output each state name
MOV AH,072H ; ZIPKEY function number ZK_ST_ABBR
INT 179 ; fetch the state abbreviation
STOSW ; output the abbreviation
MOV AL,' ' ; load blank
STOSB ; output an intervening blank
MOV AH,073H ; ZIPKEY function number ZK_ST_NAME
INT 179 ; output the full state name
MOV AX,0A0DH ; load CRLF
STOSW ; output CRLF to end this line
INC BL ; increment BL to the next state code
LOOP L1 ; loop to output the next state
P-13
; output to memory the list of valid zipcodes for region 474
MOV DX,474 ; load the region number
MOV DI,08000H ; load the output pointer
MOV CH,0 ; the first zipcode has bottom digits 00
L2: ; loop here to output each entry
MOV AH,075H ; ZIPKEY function number ZK_ZIP_ST
INT 179 ; check the validity of this zipcode
JC L3 ; skip if this is not a valid zipcode
MOV BL,AL ; zipcode valid: copy state code to BL
MOV AH,074H ; ZIPKEY function number ZK_ZIP_DIGITS
INT 179 ; output the zipcode digits
MOV AL,' ' ; load blank
STOSB ; output an intervening blank
CALL CITY_ST_CRLF ; output the city, state, and CRLF
L3:
INC CH ; increment the bottom 2 digits counter
CMP CH,100 ; have we completed the region?
JB L2 ; loop if not, to output the next line
; output a list of Illinois cities starting with RO
MOV DI,08000H ; load the output pointer
MOV BX,'LI' ; characters IL are reversed on the 8086
MOV AH,071H ; ZIPKEY function number ZK_ABBR_ST
INT 179 ; fetch the state code for this abbreviation
MOV BL,AL ; copy the state code to BL
PUSH CS ; push our code segment
POP DS ; set DS to our code segment
MOV SI,OFFSET RO_NAME ; point to "RO" city specification
MOV AH,078H ; ZIPKEY function number ZK_STCITY_ZIP
INT 179 ; get the list of entries for this city
JC L4 ; skip if the list was empty
CALL OUT_ENTRIES
L4:
; output a list of Nomes in the United States
MOV DI,08000H ; load the output pointer
PUSH CS ; push our code segment
POP DS ; set DS to our code segment
MOV SI,OFFSET NOME_NAME ; point to "Nome" specification
MOV BL,0 ; first state code is zero
JMP L6 ; jump into loop
L5: ; loop here for each matching state
PUSH AX ; save the state code
CALL OUT_ENTRIES ; output the entries for this state
POP BX ; restore the state code to BL
INC BX ; increment to the next state
L6:
MOV AH,079H ; ZIPKEY function number ZK_CITY_ZIP
INT 179 ; find a state with the desired city
JNC L5 ; loop if found, to make display
P-14
; set the maximum city width to 17
MOV BL,17 ; load the desired city width
MOV BH,0FFH ; code signals that we load width only
MOV AH,07CH ; ZIPKEY function number ZK_RESTORE
INT 179 ; set the city width
; save and restore ZIPKEY context
MOV AH,07BH ; ZIPKEY function number ZK_SAVE
INT 179 ; fetch the ZIPKEY context
PUSH BX ; push the context onto our stack
PUSH CX
PUSH DX
; ....
POP DX ; pop the saved context
POP CX
POP BX
MOV AH,07CH ; ZIPKEY function number ZK_RESTORE
INT 179 ; restore the ZIPKEY context
; popup a window as if the first hotkey were pressed
MOV AH,07DH ; ZIPKEY function number ZK_POPUP
MOV BL,0 ; index for the first hotkey is zero
INT 179 ; popup the ZIPKEY window
; insert keystrokes for zipcode 47401, as if alternate
; exit key F1 had been pressed
MOV DX,474 ; load the region number 474
MOV CH,01 ; load the last two digits 01
MOV BX,03B00 ; load the BIOS code for the F1 key
MOV AH,077H ; ZIPKEY function number ZK_ZIP_KEYS
INT 179 ; insert keystrokes for 47401 entry
; toggle the activation of ZIPKEY's hotkeys
MOV BL,3 ; control code for "toggle"
MOV AH,07FH ; ZIPKEY function number ZK_SWITCH
INT 179 ; toggle the activation of hotkeys
P-15
; output to DI a list of sample cities for area code 512
MOV BP,512 ; load the area code number
MOV DI,08000H ; load the output pointer
MOV DX,BP ; set DX to the area code
CALL OUT_DX3 ; output the area code
MOV BX,BP ; copy the area code to BX, for ZK_AREA_ST
MOV AH,080H ; function code for ZK_AREA_ST
INT 179 ; set AL to the state code for area code BX
JC OUT_CRLF ; exit if the area code did not exist
MOV BL,AL ; we have a state code: copy it to BL
MOV AH,073H ; function code for ZK_ST_NAME
INT 179 ; output the name of this area code's state
CALL OUT_CRLF ; output a CRLF to complete the header line
CMP DX,1000 ; was it a Canadian area code?
JAE OUT_CRLF ; skip if it was
L7: ; loop here to check each zip region
PUSH DI ; save the output pointer
ADD DI,6 ; advance pointer to the city-name column
MOV AH,07EH ; function code for ZK_REGION_CITY
INT 179 ; output the city name for this region
CMP BX,BP ; does the city have the correct area code?
MOV AX,DI ; save the end-of-line output pointer
POP DI ; restore the start-of-line output pointer
JNE L8 ; cancel the line if it wasn't our area code
PUSH AX ; we do have our area code: save end pointer
MOV AX,' ' ; load two blanks
STOSW ; output a two-blank indentation
CALL OUT_DX3 ; output the area code
POP DI ; restore the end-of-line pointer
CALL OUT_CRLF ; output the terminating CRLF
L8:
INC DX ; advance DX to the next zip region
LOOP L7 ; loop to check the next region
P-16
CITY_ST_CRLF: ; subroutine for outputting a city line
PUSH DX ; preserve register across call
MOV AH,076H ; ZIPKEY function number ZK_ZIP_CITY
INT 179 ; output the city name
MOV DX,BX ; copy the area code to DX, for output
MOV BL,AL ; copy the state code to BL
MOV AL,' ' ; load blank
STOSB ; output an intervening blank
MOV AH,072H ; ZIPKEY function number ZK_ST_ABBR
INT 179 ; fetch the state abbreviation
STOSW ; output the state abbreviation
MOV AX,'( ' ; load a space and a left paren
STOSW ; output a space and a left paren
CALL OUT_DX3 ; output the area code
DEC DI ; retract the trailing blank
MOV AL,')' ; load a right paren
STOSB ; output a right paren
POP DX ; restore clobbered register
OUT_CRLF: ; subroutine for outputting line terminator
MOV AX,0A0DH ; load CRLF
STOSW ; output CRLF
RET
OUT_DX3: ; subroutine for outputting 3-digit DX
PUSH CX ; preserve register across call
MOV CH,0FFH ; CH code suppresses the final two digits
MOV AH,074H ; function code for ZK_ZIP_DIGITS
INT 179 ; output the 3-digit code
MOV AL,' ' ; load blank
STOSB ; output a trailing blank
POP CX ; restore clobbered register
RET
P-17
OUT_ENTRIES: ; subroutine for outputting a cities-range
MOV BL,0 ; load the first entry number
L9: ; loop here to output each entry
PUSH BX ; save the entry number during output
PUSH DI ; save the starting output pointer
ADD DI,5 ; advance beyond the zipcode we will output
MOV AX,' ' ; load blanks
STOSW ; blank out the trailing range slot
STOSW ; slot plus trailing blank are 4 characters
POP DI ; restore the pointer to the line start
MOV AH,07AH ; ZIPKEY function number ZK_CASE_ZIP
INT 179 ; look up this entry
MOV BL,AL ; copy the state code to BL
CMP CL,CH ; is there only one zipcode?
JE L10 ; skip if single zipcode: slot stays blank
PUSH DI ; it is a range: save output pointer
ADD DI,3 ; advance the output pointer
MOV AH,074H ; ZIPKEY function number ZK_ZIP_DIGITS
INT 179 ; output the end-value zipcode digits
POP DI ; restore starting output pointer
ES MOV BYTE PTR [DI+5],'-' ; place the trailing hyphen
MOV CH,CL ; copy the start-value to CH
L10:
MOV AH,074H ; ZIPKEY function number ZK_ZIP_DIGITS
INT 179 ; output the start-value zipcode digits
ADD DI,4 ; advance beyond the end-value slot
CALL CITY_ST_CRLF ; output the city, state, CRLF
POP BX ; restore the entry number BL
INC BL ; increment the entry number
CMP BL,BH ; have we exhausted the entries?
JB L9 ; loop if not, to output the next entry
RET